package org.mullin.stratego.shared;

import java.util.ArrayList;
import java.util.List;

/**
 * State of a game of Stratego.
 * 
 * @author kevin.mullin
 */
public class State {
		
	public static final int ROWS = 10;
	public static final int COLS = 10;
	
	public static final char RED = 'R';
	public static final char BLUE = 'B';
	public static final char NEUTRAL = 'N';	
	
	/** A piece of water on the board.*/
	public static final Piece LAND = new Piece(Color.NEUTRAL, Rank.LAND);
	/** A piece of land on the board.*/
	public static final Piece WATER = new Piece(Color.NEUTRAL, Rank.WATER);
	
	private Piece board[][];
	private int turn;
	
	private boolean gameEnded;
	private int winner;	
	
	public State() {
		board = new Piece[ROWS][COLS];
		// board starts empty
		for (int i = 0; i < ROWS; i++) {
			for (int j = 0; j < COLS; j++) {
				board[i][j] = LAND;
			}
		}
		// set water squares
		board[4][2] = WATER;
		board[4][3] = WATER;
		board[5][2] = WATER; 
		board[5][3] = WATER;
		board[4][6] = WATER; 
		board[4][7] = WATER;
		board[5][6] = WATER; 
		board[5][7] = WATER;
		
		turn = Color.RED;
	}
	
	/**
	 * Copy and return a state.
	 * @param other State to be copied.
	 * @return The copy.
	 */
	public static State copyOf(State other) {
		State ret = new State();
		ret.turn = other.turn;
		for (int i = 0; i < ROWS; i++) {
			for (int j = 0; j < COLS; j++) {
				ret.board[i][j] = other.board[i][j];
			}
		}		
		return ret;
	}
	
	/**
	 * Transition state to end of game.
	 */
	public void gameOver() {
		gameEnded = true;
		winner = turn;
	}
	
	/**
	 * Assigns a piece to the board at the provided coordinate.
	 * 
	 * @param p Piece to place.
	 * @param c Coordinate to stick piece.
	 */
	public void setPiece(Piece p, Coord c) {
		int row = c.x, col = c.y;
		
		if (row < 0 || row > ROWS || col < 0 || col > COLS) {
			throw new IllegalArgumentException();
		}
		board[row][col] = p;
	}
	
	/**
	 * Return the piece at provided coordinate on the board.
	 * 
	 * @param c Coordinate on board to look at.
	 * @return Piece at coordinate c.
	 */
	public Piece getPiece(Coord c) {
		int row = c.x, col = c.y;
		
		if (row < 0 || row > ROWS || col < 0 || col > COLS) {
			throw new IllegalArgumentException();
		}
		return board[row][col];
	}
	
	/**
	 * Check if any piece is at coordinate c on the board.
	 * 
	 * @param c Coord to check.
	 * @return False if coord is occupied, true otherwise.
	 */
	public boolean isEmptySpot(Coord c) {
		return getPiece(c).equals(LAND);
	}
	
	/**
	 * Get the color of current turn.
	 * 
	 * @return Color of current turn.
	 */
	public int getTurn() {
		return turn;
	}
	
	public void setTurn(int color) {
		turn = color;
	}
	
	/**
	 * Has the game ended?
	 * 
	 * @return true if game is over, false otherwise.
	 */
	public boolean isGameOver() {
		return gameEnded;
	}
	
	/**
	 * Get the color of the winner.
	 * 
	 * @return winning color or neutral if game is in progress.
	 */
	public int getWinner() {
		if (gameEnded) {
			return winner;
		}
		return Color.NEUTRAL;
	}
	
	/**
	 * Switch turn colors.
	 */
	public void transition() {
		turn = turn ^ 1;
	}
	
	@Override
	public boolean equals(Object rhs) {
		if (null == rhs) {
			return false;
		}
		if (!(rhs instanceof State)) {
			return false;
		}
		State other = (State)rhs;
		
		for (int i = 0; i < ROWS; i++) {
			for (int j = 0; j < COLS; j++) {
				if (!board[i][j].equals(other.board[i][j])) {
					return false;
				}
			}
		}
		return turn == other.turn;
	}
	
	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < ROWS; i++) {
			for (int j = 0; j < COLS; j++) {
				sb.append(board[i][j]);
				sb.append(' ');
			}
			sb.append('\n');
		}
		return sb.toString();
	}
	
	/**
	 * Serialize a state into a string.
	 * 
	 * @param state
	 * @return string with serialized state
	 */
	public static String serialize(State state) {
		StringBuilder sb = new StringBuilder();
		
		sb.append(state.getTurn());
		for (int i = 0; i < ROWS; i++) {
			for (int j = 0; j < COLS; j++) {
				Piece p = state.board[i][j];
				switch (p.color) {
				case Color.RED:
					sb.append(RED);
					break;
				case Color.BLUE:
					sb.append(BLUE);
					break;
				case Color.NEUTRAL:
					sb.append(NEUTRAL);
					break;
				}
				sb.append(p.rank.ordinal());
				char s = (p.shown /*|| p.color == state.getTurn()*/) ? 'T' : 'F';
				sb.append(s);
			}
		}
		
		return sb.toString();
	}
		
	/**
	 * Create state from a serialized representation.
	 * 
	 * @param s serialized state
	 * @return state
	 */
	public static State deserialize(String s) {
		State ret = new State();
		
		char turn = s.charAt(0);
		ret.setTurn(turn == '0' ? Color.BLUE : Color.RED);
		
		int i = 1, j = 0;
		
		int shitcount = 0;
		while (i < s.length() && shitcount < 100 /* FUCK THAT SHIT, 100PIECES*/) {
			shitcount++;						
			char p = s.charAt(i++);
			int ord = 0;
			char r = s.charAt(i++);

			ord += Character.digit(r, 10);
			if (i < s.length() && Character.isDigit(s.charAt(i))) {
				r = s.charAt(i++);
				ord *= 10;
				ord += Character.digit(r, 10);
			}
			char shown = s.charAt(i++);
			
			Piece piece;
			if (p != NEUTRAL) {
				Rank rank = Rank.values()[ord];
				piece = new Piece( p==RED ? Color.RED : Color.BLUE, rank);
				piece.shown = (shown == 'T') ? true : false;
			} else {
				piece = (Rank.values()[ord] == Rank.LAND) ? LAND : WATER; 
			}
			
			ret.setPiece(piece, new Coord(j/10, j%10));
			j++;
		}
		return ret; 
	}
}
